/*
 superNode.go
 Created by hupfei on 2019-08-05
*/

package model

import (
	"database/sql"
	"fmt"
	"github.com/jmoiron/sqlx"
	"github.com/pkg/errors"
	"strings"
	"time"
	"zimuzu_cvn_web_api/config"
	. "zimuzu_cvn_web_api/pkg/e"
	"zimuzu_cvn_web_api/pkg/errno"
)

//审核模式：1-需审核后加入，2-禁止任何人加入
const VerifyModeNormal = 1
const VerifyModeForbid = 2

//矿工状态：10：待启用，20：启用中， 30：被超级节点踢出，40：自己退出
const MinerStatusNormal = 10
const MinerStatusMining = 20
const MinerStatusUnbindBySuperNode = 30
const MinerStatusUnbindBySelf = 40

//旷工申请的审核状态：0-审核中，1-通过，2-拒绝，3-已过期
const MinerApplyStatusNormal = 0
const MinerApplyStatusSuccess = 1
const MinerApplyStatusRefused = 2
const MinerApplyStatusExpired = 3

//超级节点信息
type SuperNodeInfo struct {
	Uid           int64  `json:"uid,omitempty" db:"uid"`
	NodeId        int64  `json:"nodeId,omitempty" db:"node_id"`
	Status        int    `json:"status,omitempty" db:"status"`
	Des           string `json:"des" db:"des"`
	Introduction  string `json:"introduction" db:"introduction"`
	Name          string `json:"name" db:"name"`
	Pic           string `json:"pic" db:"pic"`
	Wechat        string `json:"wechat" db:"wechat"`
	WechatCodePic string `json:"wechatCodePic" db:"wechatCodePic"`
	MaxNodeNum    int    `json:"maxNodeNum" db:"max_node_num"`
	VerifyMode    int    `json:"verifyMode" db:"verify_mode"`
}

//超级节点结算信息
type SuperNodePayment struct {
	CreateTime string  `json:"createTime" db:"date"`
	Cvnt       float64 `json:"cvnt" db:"cvnt"`
	Title      string  `json:"title" db:"title"`
	Type       int     `json:"type" db:"type"`
}

//矿工信息
type MinerInfo struct {
	Uid           int64   `json:"uid" db:"uid"`
	SuperNodeId   int64   `json:"superNodeId" db:"super_node_id"`
	Status        int     `json:"status" db:"status"`
	JoinTime      int     `json:"joinTime" db:"join_time"`
	BadRecords    int64   `json:"bad_records" db:"bad_records"`
	Nickname      string  `json:"nickname" db:"nickname"`
	CreateTime    string  `json:"createTime" db:"create_time"`
	TopStatus     int     `json:"topStatus" db:"top_status"`
	TopTime       int     `json:"topTime" db:"top_time"`
	MaxNodeNum    int     `json:"maxNodeNum" db:"max_node_num"`
	IncomeAbility float64 `json:"incomeAbility" db:"income_ability"`
}

// 矿工申请信息
type MinerApplyInfo struct {
	Uid        int64  `json:"uid" db:"uid"`
	SuperUid   int64  `json:"superUid" db:"super_uid"`
	NodeNum    int    `json:"nodeNum" db:"node_num"`
	Status     int    `json:"status" db:"status"`
	CreateTime string `json:"createTime" db:"create_time"`
}

// 超级节点
type MinerSuperId struct {
	SuperUid int64 `form:"super_uid" json:"super_uid"`
}

/*
 * @ Author: hupfei
 * @ Description: 查询超级节点
 **/
func SuperNodeInfoByUid(uid int64) (node SuperNodeInfo, err error) {
	err = sqlx.Get(config.C.DB.DB, &node, "SELECT node_id, status, name, max_node_num, verify_mode FROM super_node WHERE uid = ?", uid)
	if err == sql.ErrNoRows {
		err = nil
	}
	if err != nil {
		Log("err", "SuperNodeInfoByUid：", uid, err.Error())
	}
	return
}

//获取超级节点姓名
func GetSuperNodeNameByMinerUid(minerUid int64) (name string, err error) {
	err = sqlx.Get(config.C.DB.DB, &name, "SELECT IFNULL(name, '') FROM super_node_miner miner LEFT JOIN super_node super ON miner.super_node_id = super.node_id WHERE miner.uid = ?", minerUid)
	if err == sql.ErrNoRows {
		err = nil
	}
	if err != nil {
		Log("err", "GetSuperNodeNameByMinerUid：", err.Error())
	}
	return
}

/*
 * @ Author: hupfei
 * @ Description: 根据超级节点节点id查询超级节点信息
 **/
func SuperNodeInfoByNodeId(superNodeId int64) (node SuperNodeInfo, err error) {
	err = sqlx.Get(config.C.DB.DB, &node, "SELECT uid, status, max_node_num FROM super_node WHERE node_id = ?", superNodeId)
	if err == sql.ErrNoRows {
		err = nil
	}
	if err != nil {
		Log("err", "SuperNodeInfoByNodeId：", superNodeId, err.Error())
	}
	return
}

/*
 * @ Author: hupfei
 * @ Description: 查询矿工信息
 **/
func GetMinerInfoByUid(uid int64) (miner MinerInfo, err error) {
	err = sqlx.Get(config.C.DB.DB, &miner, "SELECT uid, super_node_id, status, join_time, bad_records, create_time, top_status, top_time, max_node_num, income_ability "+
		"FROM super_node_miner WHERE uid = ? limit 1", uid)
	if err == sql.ErrNoRows {
		err = nil
	}
	if err != nil {
		Log("err", "GetMinerInfoByUid：", uid, err.Error())
	}
	return
}

/*
 * @ Author: hupfei
 * @ Description: 全网已有超级节点数
 **/
func SuperNodeCount() (count int, err error) {
	err = sqlx.Get(config.C.DB.DB, &count, "SELECT COUNT(*) FROM super_node WHERE status = 10")
	if err == sql.ErrNoRows {
		err = nil
	}
	if err != nil {
		Log("err", "SuperNodeCount：", err.Error())
	}
	return
}

/*
 * @ Author: hupfei
 * @ Description: 超级节点昨日总收益
 * @ Params: souce 1累计收益  2昨日收益
 **/
func SuperNodeIncome(nodeId int64, source int) (string, error) {
	var re sql.NullString
	var err error
	if source == 1 {
		err = sqlx.Get(config.C.DB.DB, &re, "SELECT sum(cvnt) FROM `super_node_payment` WHERE node_id = ?", nodeId)
	} else {
		err = sqlx.Get(config.C.DB.DB, &re, "SELECT sum(cvnt) FROM `super_node_payment` WHERE node_id = ? AND date = DATE_SUB(curdate(),INTERVAL 1 DAY)", nodeId)
	}
	if err == sql.ErrNoRows {
		err = nil
	}
	if err != nil {
		Log("err", "SuperNodeIncome: ", nodeId, "source：", source, err.Error())
	}
	return re.String, err
}

/*
 * @ Author: hupfei
 * @ Description: 获取超级节点下矿工贡献
 **/
type IncomeInfo struct {
	Uid           int64   `json:"uid" db:"uid"`
	CreateTime    string  `json:"createTime" db:"create_time"`
	Nickname      string  `json:"nickname" db:"nickname"`
	TotalCvnt     string  `json:"totalCvnt" db:"totalCvnt"`
	YesterdayCvnt string  `json:"yesterdayCvnt" db:"yesterdayCvnt"`
	Status        int     `json:"status" db:"status"`
	NodeNum       int     `json:"nodeNum" db:"nodeNum"`
	MiningNodeNum int     `json:"miningNodeNum" db:"miningNodeNum"`
	MaxNodeNum    int     `json:"maxNodeNum" db:"max_node_num"`
	IncomeAbility float64 `json:"incomeAbility" db:"income_ability"`
	RouterNum     int     `json:"routerNum" db:"routerNum"`
	LinuxNum      int     `json:"linuxNum" db:"linuxNum"`
	PcNum         int     `json:"pcNum" db:"pcNum"`
}

func GetMinerInComeList(superNodeId int64, page, per int) (miner []IncomeInfo, err error) {
	start := (page - 1) * per
	err = sqlx.Select(config.C.DB.DB, &miner, "SELECT u.nickname, u.uid, m.max_node_num, FROM_UNIXTIME(m.join_time, '%Y/%m/%d') AS create_time, "+
		"SUM(IFNULL(pay.super_cvn, 0)) AS totalCvnt, SUM(IF(pay.date >= date_sub(curdate(), INTERVAL 1 DAY), super_cvn, 0)) AS yesterdayCvnt, m.top_status AS status, m.income_ability"+
		" FROM super_node n"+
		" LEFT JOIN super_node_miner m ON n.node_id = m.super_node_id"+
		" INNER JOIN user u ON m.uid = u.uid"+
		" LEFT JOIN mg_node_payment pay ON pay.uid = m.uid AND pay.super_node_id = m.super_node_id AND pay.status = 1"+
		" WHERE n.node_id = ? AND m.status = 20"+
		" GROUP BY m.uid ORDER BY status DESC, yesterdayCvnt DESC, create_time DESC, m.uid LIMIT ?, ?", superNodeId, start, per)
	if err != nil {
		Log("err", "GetMinerInComeList：", superNodeId, err.Error())
	}
	return miner, err
}

/*
 * @ Author: hupfei
 * @ Description: 获取收益明细列表
 **/
func GetSuperNodePaymentList(nodeId int64, page, per int) (info []SuperNodePayment, err error) {
	start := (page - 1) * per
	err = sqlx.Select(config.C.DB.DB, &info, "SELECT cvnt, IF(type=10,'矿工分红', '首年奖励') AS title, DATE_FORMAT(date,'%Y-%m-%d') AS date, type "+
		"FROM super_node_payment WHERE node_id = ? ORDER BY create_time DESC LIMIT ?, ?", nodeId, start, per)
	if err != nil {
		Log("err", "GetSuperNodePaymentList", nodeId, err.Error())
	}
	return info, err
}

/*
 * @ Author: hupfei
 * @ Description: 检查矿工是否存在
 **/
func CheckMinerExist(uid int64) bool {
	var count sql.NullInt64
	err := sqlx.Get(config.C.DB.DB, &count, "SELECT count(*) FROM super_node_miner WHERE uid = ?", uid)
	if err == sql.ErrNoRows {
		err = nil
	}
	if err != nil {
		Log("err", "CheckMinerExist 失败:", err.Error())
	}
	return count.Int64 > 0
}

/*
 * @ Author: hupfei
 * @ Description: 检查矿工是否存在
 **/
func CheckMinerLiveExist(uid int64) bool {
	var count sql.NullInt64
	err := sqlx.Get(config.C.DB.DB, &count, "SELECT count(*) FROM super_node_miner WHERE uid = ? AND `status` = 10", uid)
	if err == sql.ErrNoRows {
		err = nil
	}
	if err != nil {
		Log("err", "CheckMinerExist 失败:", err.Error())
	}
	return count.Int64 > 0
}

/*
 * @ Author: hupfei
 * @ Description: 检查用户是否是超级节点
 **/
func CheckUserIsSuperNode(uid int64) (bool, error) {
	var count int
	row := config.C.DB.DB.QueryRowx("SELECT count(*) FROM super_node WHERE uid = ? AND status = 10", uid)
	err := row.Scan(&count)
	if err != nil {
		return false, err
	}
	if count == 0 {
		return false, nil
	}
	return true, nil
}

/*
 * @ Author: hupfei
 * @ Description: 更新矿工信息
 **/
func UpdateMinerInfo(miner MinerInfo) error {
	if miner.Uid <= 0 {
		return errors.New("矿工uid不能为空")
	}
	sqlStr := "UPDATE super_node_miner SET"
	if miner.SuperNodeId > 0 {
		sqlStr += fmt.Sprintf(" super_node_id = %d,", miner.SuperNodeId)
	}
	if miner.Status > 0 {
		sqlStr += fmt.Sprintf(" status = %d,", miner.Status)
	}
	if len(miner.CreateTime) > 0 {
		sqlStr += fmt.Sprintf(" create_time = %s,", miner.CreateTime)
	}
	if miner.JoinTime > 0 {
		sqlStr += fmt.Sprintf(" join_time = %d,", miner.JoinTime)
	}
	if miner.TopStatus > 0 {
		sqlStr += fmt.Sprintf(" top_status = %d,", miner.TopStatus)
	}
	if miner.TopTime > 0 {
		sqlStr += fmt.Sprintf(" top_time = %d,", miner.TopTime)
	}
	sqlStr = strings.TrimSuffix(sqlStr, ",")
	sqlStr += fmt.Sprintf(" WHERE uid = %d", miner.Uid)

	_, err := config.C.DB.DB.Exec(sqlStr)
	if err != nil {
		Log("err", "UpdateMinerInfo：", miner.Uid, err.Error())
	}
	return err
}

//更新矿工可开设节点的最大数
func UpdateMinerMaxNodeNum(minerUid, superNodeId int64, nodeNum int) error {
	res, err := config.C.DB.DB.Exec("UPDATE super_node_miner SET max_node_num = max_node_num + ? WHERE uid = ? AND super_node_id = ?", nodeNum, minerUid, superNodeId)
	if err != nil {
		Log("err", "UpdateMinerMaxNodeNum 失败：", err.Error())
		return errno.DbError
	}
	r1, _ := res.RowsAffected()
	if r1 <= 0 {
		return errno.IllegalErr
	}
	return nil
}

/*
 * @ Author: hupfei
 * @ Description: 查询超级节点下的矿工信息
 * @ params: source 1已开启挖矿的矿工  2未开启挖矿的矿工
 **/
func GetMinerList(superNodeId int64, page, per, source int) (miner []MinerInfo, err error) {
	if source <= 0 {
		source = 1
	}
	start := (page - 1) * per

	sqlStr := "SELECT node.uid, IFNULL(u.nickname, node.uid) AS nickname,"
	if source == 1 {
		//成为矿工的时间
		sqlStr += " FROM_UNIXTIME(node.join_time, '%Y/%m/%d') AS create_time"
	} else if source == 2 {
		//邀请的时间
		sqlStr += " FROM_UNIXTIME(node.create_time, '%Y/%m/%d') AS create_time"
	}
	sqlStr += fmt.Sprintf(" FROM super_node_miner AS node LEFT JOIN user AS u ON node.uid = u.uid WHERE super_node_id = %d", superNodeId)
	if source == 1 {
		//已开启挖矿的矿工
		sqlStr += " AND node.status = 20"
	} else if source == 2 {
		//未开启挖矿的矿工
		sqlStr += " AND node.status != 20"
	}
	sqlStr += fmt.Sprintf(" ORDER BY create_time DESC LIMIT %d, %d", start, per)

	err = sqlx.Select(config.C.DB.DB, &miner, sqlStr)
	if err != nil {
		Log("err", "GetMinerList：", superNodeId, "source：", source, err.Error())
	}
	return miner, err
}

/*
 * @ Author: hupfei
 * @ Description: 获取各节点贡献信息
 * @ params: source 1 linux  2 router  3 pc
 **/
type miningInfo struct {
	Name          string `json:"name" db:"name"`
	TotalCvnt     string `json:"totalCvnt" db:"totalCvnt"`
	YesterdayCvnt string `json:"yesterdayCvnt" db:"yesterdayCvnt"`
}

func GetMinerNodeMiningList(uid, superNodeId int64, page, per int, source int) (info []miningInfo, err error) {
	if source <= 0 {
		source = 1
	}
	start := (page - 1) * per

	var nodeType int
	if source == 1 {
		nodeType = NodeTypeLinux
	} else if source == 2 {
		nodeType = NodeTypeRouter
	} else {
		nodeType = NodeTypePc
	}

	err = sqlx.Select(config.C.DB.DB, &info, "SELECT n.name, IFNULL(SUM(p.super_cvn),0) AS totalCvnt,IFNULL(SUM(IF (p.date>=date_sub(curdate(),INTERVAL 1 DAY),p.super_cvn,0)),0) AS yesterdayCvnt "+
		"FROM mg_node n LEFT JOIN mg_node_payment p ON p.node_id=n.node_id AND p.status=1 AND p.super_node_id = ? "+
		"WHERE n.uid = ? AND n.status=1 and n.type = ? and n.token_status != 1 "+
		"GROUP BY n.node_id ORDER BY n.node_id DESC LIMIT ?, ?", superNodeId, uid, nodeType, start, per)
	if err != nil {
		Log("err", "GetMinerRouterMiningList：", uid, ":", superNodeId, "source：", source, err.Error())
	}
	return info, err
}

//查询所有超级节点
func GetSuperNodeInfoList() (info []SuperNodeInfo, err error) {
	err = sqlx.Select(config.C.DB.DB, &info, "SELECT node_id, uid, name, CONCAT('"+config.C.Domains.YqbAppMenu+"', 'super/', uid, '_pic.png') as pic, "+
		"CONCAT('"+config.C.Domains.YqbAppMenu+"', 'super/', uid, '_code.png') as wechatCodePic, wechat, des, introduction, max_node_num "+
		"FROM super_node WHERE status = 10 AND show_status = 1 AND verify_mode != 2 ORDER BY node_id")
	if err != nil {
		Log("err", "GetSuperNodeInfoList失败：", err.Error())
	}
	return
}

//获取超级节点旗下已质押的节点数（不包含路由器）
func GetSuperNodePledgedNodeNum(superNodeId int64) (num int, err error) {
	err = sqlx.Get(config.C.DB.DB, &num, "SELECT COUNT(*) FROM mg_node node LEFT JOIN super_node_miner miner ON node.uid = miner.uid "+
		"WHERE miner.super_node_id = ? AND miner.status = ? AND node.status != 2 AND node.token_status != 1 AND node.type != ?", superNodeId, MinerStatusMining, NodeTypeRouter)
	if err != nil {
		Log("err", "GetSuperNodePledgedNodeNum 失败：", err.Error())
	}
	return
}

type SuperNodePledgedNodeNum struct {
	Num    int   `json:"num" db:"num"`
	NodeId int64 `json:"nodeId" db:"super_node_id"`
}

//所有超级节点的剩余名额
func GetAllSuperNodePledgedNodeNum() (list []SuperNodePledgedNodeNum, err error) {
	err = sqlx.Select(config.C.DB.DB, &list, "SELECT miner.super_node_id, COUNT(*) AS num FROM mg_node node LEFT JOIN super_node_miner miner ON node.uid = miner.uid "+
		"WHERE miner.status = ? AND node.status != 2 AND node.token_status != 1 AND node.type != ? GROUP BY miner.super_node_id", MinerStatusMining, NodeTypeRouter)
	if err != nil {
		Log("err", "GetAllSuperNodePledgedNodeNum 失败：", err.Error())
	}
	return
}

//超级节点旗下节点7日平均收益
func GetSuperNodeAverageIncome(superNodeId int64) (cvnt float64, err error) {
	err = sqlx.Get(config.C.DB.DB, &cvnt, "select IFNULL(AVG(income_ability), 0) FROM super_node_miner WHERE super_node_id = ? AND `status` = ?", superNodeId, MinerStatusMining)
	if err != nil {
		Log("err", "GetSuperNodeAverageIncome 失败：", err.Error())
	}
	return
}

//是否已经申请过加入该超级节点
func CheckMinerHasApplied(uid int64, superUid int64) bool {
	var count sql.NullInt64
	err := sqlx.Get(config.C.DB.DB, &count, "SELECT count(*) FROM super_node_apply WHERE uid = ? AND super_uid = ? AND status = ?", uid, superUid, MinerApplyStatusNormal)
	if err == sql.ErrNoRows {
		err = nil
	}
	if err != nil {
		Log("err", "CheckMinerHasApplied 失败:", err.Error())
	}
	return count.Int64 > 0
}

//新增申请加入超级节点记录
func InsertSuperNodeApplyInfo(uid int64, superUid int64, nodeNum int) (err error) {
	res, err := config.C.DB.DB.Exec(`INSERT INTO super_node_apply(uid, super_uid, node_num, create_time) VALUES (?, ?, ?, ?)`, uid, superUid, nodeNum, time.Now().Unix())
	if err != nil {
		Log("err", "InsertSuperNodeApplyInfo 失败：", err.Error())
		return errno.DbError
	}
	r, err := res.RowsAffected()
	if err != nil {
		Log("err", "InsertSuperNodeApplyInfo：RowsAffected:", uid, err.Error())
		return errno.DbError
	}
	if r <= 0 {
		return errno.DbError
	}
	return nil
}

//更新矿工审核状态
func UpdateMinerApplyStatus(minerUid, superUid int64, applyStatus int) error {
	res, err := config.C.DB.DB.Exec("UPDATE super_node_apply SET status = ? WHERE uid = ? AND super_uid = ?", applyStatus, minerUid, superUid)
	if err != nil {
		Log("err", "UpdateMinerApplyStatus 失败：", err.Error())
		return errno.DbError
	}
	r, err := res.RowsAffected()
	if err != nil {
		Log("err", "UpdateMinerApplyStatus 失败：RowsAffected:", err.Error())
		return errno.DbError
	}
	if r <= 0 {
		Log("err", "影响的行数为：", r)
		return errno.DbError
	}
	return nil
}

//矿工申请记录
type MinerApplyRes struct {
	Uid           int64   `json:"uid" db:"uid"`
	NodeNum       int     `json:"nodeNum" db:"node_num"`
	Nickname      string  `json:"nickname" db:"nickname"`
	IncomeAbility float64 `json:"incomeAbility" db:"income_ability"`
}

func GetMinerApplyList(uid int64, page, per int) (list []MinerApplyRes, err error) {
	start := (page - 1) * per

	err = sqlx.Select(config.C.DB.DB, &list, "SELECT a.uid, u.nickname, a.node_num, IFNULL(m.income_ability, 0) AS income_ability "+
		"FROM super_node_apply a INNER JOIN user u ON a.uid = u.uid LEFT JOIN super_node_miner m ON a.uid = m.uid "+
		"WHERE a.super_uid = ? AND a.status = 0 ORDER BY a.create_time DESC LIMIT ?, ?", uid, start, per)
	if err != nil {
		Log("err", "GetMinerApplyList 失败：", uid, err.Error())
	}
	return
}

//矿工申请记录
func GetMinerApplyInfo(minerUid int64, superUid int64) (info MinerApplyInfo, err error) {
	err = sqlx.Get(config.C.DB.DB, &info, "SELECT node_num, status FROM super_node_apply WHERE uid = ? AND super_uid = ? AND status = ?", minerUid, superUid, MinerApplyStatusNormal)
	if err == sql.ErrNoRows {
		return info, errno.RecordError
	}
	if err != nil {
		Log("err", "GetMinerApplyInfo 失败:", err.Error())
		return info, errno.DbSearchError
	}
	return info, nil
}

//申请加入总数
func GetApplyNum(uid int64) (count int, err error) {
	err = sqlx.Get(config.C.DB.DB, &count, "SELECT COUNT(*) FROM super_node_apply WHERE super_uid = ? AND status = ?", uid, MinerApplyStatusNormal)
	if err != nil {
		Log("err", "失败 GetApplyNum：", err.Error())
	}
	return
}

// 普通用户申请旷工
func NormalUserApplyMiner(Uid, superUid int64) (err error) {

	db := config.C.DB.DB
	// 先看旷工表是否有记录
	var count int
	err = sqlx.Get(db, &count, "SELECT Count(*) FROM super_node_miner WHERE uid = ?", Uid)
	if err != nil {
		return err
	}

	if count > 0 {
		r := sqlx.MustExec(db, "UPDATE super_node_miner SET super_node_id = ?, status = ?, join_time = ?"+
			" WHERE uid = ?", superUid, 20, time.Now().Unix(), Uid)
		row1, err := r.RowsAffected()
		if err != nil {
			return err
		}
		if row1 <= 0 {
			return errno.ApplyMinerExistsErr
		}
	} else {
		r2 := sqlx.MustExec(db, "INSERT INTO super_node_miner(uid, super_node_id, status, create_time, join_time)"+
			" VALUES (?, ?, ?, ?, ?)", Uid, superUid, 20, time.Now().Unix(), time.Now().Unix())
		row2, err := r2.RowsAffected()
		if err != nil {
			return err
		}
		if row2 <= 0 {
			return errno.ApplyMinerExistsErr
		}
	}
	return nil
}

//同意矿工申请
func AgreeMinerApply(minerUid, superUid int64, nodeNum int, isMinerExist bool) error {
	//超级节点id
	superNode, err := SuperNodeInfoByUid(superUid)
	if err != nil {
		Log("err", err.Error())
		return errno.DbSearchError
	}

	tx, err := config.C.DB.DB.Beginx()
	if err != nil {
		Log("err", err.Error())
		return errno.DbError
	}

	if isMinerExist {
		//更新super_node_miner状态
		result, err := tx.Exec(`UPDATE super_node_miner SET super_node_id = ?, status = ?, join_time = ?, max_node_num = ?, top_status = 1, top_time = 0 WHERE uid = ?`,
			superNode.NodeId, MinerStatusMining, time.Now().Unix(), nodeNum, minerUid)
		if err != nil {
			Log("err", err.Error())
			_ = tx.Rollback()
			return errno.DbError
		}
		aff, err := result.RowsAffected()
		if err != nil {
			Log("err", err.Error())
			_ = tx.Rollback()
			return errno.DbError
		}
		if aff != 1 {
			Log("info", "影响行数为:", aff)
			_ = tx.Rollback()
			return errno.DbError
		}
	} else {
		//新增super_node_miner
		_, err := tx.Exec(`INSERT INTO super_node_miner(uid, super_node_id, status, create_time, join_time, max_node_num) VALUES (?, ?, ?, ?, ?, ?)`,
			minerUid, superNode.NodeId, MinerStatusMining, time.Now().Unix(), time.Now().Unix(), nodeNum)
		if err != nil {
			Log("err", err.Error())
			_ = tx.Rollback()
			return errno.DbError
		}
	}

	//更新super_node_apply状态
	result, err := tx.Exec(`UPDATE super_node_apply SET status = IF(super_uid=?, ?, ?) WHERE uid = ? AND status != ?`,
		superUid, MinerApplyStatusSuccess, MinerApplyStatusExpired, minerUid, MinerApplyStatusRefused)
	if err != nil {
		Log("err", err.Error())
		_ = tx.Rollback()
		return errno.DbError
	}
	aff, err := result.RowsAffected()
	if err != nil {
		Log("err", err.Error())
		_ = tx.Rollback()
		return errno.DbError
	}
	if aff < 1 {
		Log("info", "影响的行数为：", aff)
		_ = tx.Rollback()
		return errno.DbError
	}
	Log("info", "影响行数为:", aff)

	err = tx.Commit()
	if err != nil {
		Log("err", err.Error())
		return errno.DbError
	}

	return nil
}

//修改审核模式
func UpdateVerifyMode(uid int64, status int) error {
	_, err := config.C.DB.DB.Exec("UPDATE super_node SET verify_mode = ? WHERE uid = ?", status, uid)
	if err != nil {
		Log("err", "UpdateVerifyMode 失败：", err.Error())
		return errno.DbError
	}
	return nil
}

//查询会占用名额未挖矿节点数
func GetUnmineNodeNum(uid int64) (qi int, err error) {
	err = sqlx.Get(config.C.DB.DB, &qi, "SELECT count(*) FROM `mg_node` where uid = ? and status = 1 and token_status = 1 and type != 3", uid)
	return qi, err
}

//查询矿工已占用名额
func GetMineUsedQuota(uid int64) (qi int, err error) {
	err = sqlx.Get(config.C.DB.DB, &qi, "SELECT count(*) FROM `mg_node` where uid = ? and status != 2 and token_status != 1 and type != 3", uid)
	return qi, err
}

//获取加入某超级节点后的总挖矿收入
func GetMineCvnInSuperNode(uid, superNodeId int64, t int) (qi float64, err error) {
	startTime := 1574755200
	if t < startTime {
		t = startTime
	}
	err = sqlx.Get(config.C.DB.DB, &qi, "SELECT IFNULL(sum(cvn), 0) AS cvn FROM `mg_node_payment` where uid = ? and super_node_id = ? and create_time > ?", uid, superNodeId, t)
	return qi, err
}

//退出超级节点
func MinerSecede(uid int64) (err error) {
	_, err = config.C.DB.DB.Exec("UPDATE super_node_miner SET super_node_id = 0, status = 40, max_node_num = 0 WHERE uid = ?", uid)
	return err
}

// 矿工列表
func GetSuperMinerList() (res []UidList, err error) {
	err = sqlx.Select(config.C.DB.DB, &res, "SELECT uid FROM super_node_miner WHERE 1 ")
	if err != nil {
		return res, err
	}
	return res, nil
}

type AdminSuperNodeInfo struct {
	Uid          int64   `json:"uid" db:"uid" form:"targetUid" binding:"required"`
	NodeId       int64   `json:"node_id" db:"node_id" form:"node_id"`
	Status       int     `json:"status" db:"status" form:"status"`
	Des          string  `json:"des" db:"des" form:"des" binding:"required"`
	Mark         string  `json:"mark" db:"mark" form:"mark"`
	Introduction string  `json:"introduction" db:"introduction" form:"introduction"`
	Name         string  `json:"name" db:"name" form:"name" binding:"required"`
	Wechat       string  `json:"wechat" db:"wechat" form:"wechat" binding:"required"`
	PhoneArea    int     `json:"phone_area" db:"phone_area" form:"phone_area" binding:"required"`
	PhoneNumber  string  `json:"phone_number" db:"phone_number" form:"phone_number" binding:"required"`
	CreateTime   string  `json:"createTime" db:"create_time"`
	Code         int     `form:"code"`
	NodesNum     int     `json:"nodesNum"`
	IncomeTotal  float64 `json:"incomeTotal"`
}

//管理系统查询所有超级节点
func GetSuperNodeList() (info []AdminSuperNodeInfo, err error) {
	err = sqlx.Select(config.C.DB.DB, &info, "SELECT node_id, uid, name, wechat, des, introduction, mark, phone_area, phone_number, status, "+
		"FROM_UNIXTIME(create_time, '%Y-%m-%d %H:%i:%s') AS create_time "+
		"FROM super_node ORDER BY node_id DESC")
	if err != nil {
		Log("err", "GetSuperNodeList：", err.Error())
	}
	return
}

//更新超级节点信息
func UpdateSuperNodeInfo(params AdminSuperNodeInfo) (err error) {
	if params.NodeId <= 0 {
		return errors.New("node_id不能为空")
	}
	sqlStr := fmt.Sprintf("UPDATE super_node SET `status` = %d, name = '%s', wechat = '%s', des = '%s', phone_area = %d, phone_number = '%s', ",
		params.Status, params.Name, params.Wechat, params.Des, params.PhoneArea, params.PhoneNumber)
	if len(params.Mark) > 0 {
		sqlStr += fmt.Sprintf("mark = '%s', ", params.Mark)
	}
	if len(params.Introduction) > 0 {
		sqlStr += fmt.Sprintf("introduction = '%s', ", params.Introduction)
	}
	sqlStr += fmt.Sprintf("update_time = %d WHERE node_id = %d", time.Now().Unix(), params.NodeId)

	res := sqlx.MustExec(config.C.DB.DB, sqlStr)
	_, err = res.RowsAffected()
	if err != nil {
		Log("err", err.Error())
		return errno.DbError
	}
	return
}

//新增超级节点
func AddNewSuperNode(params AdminSuperNodeInfo) (err error) {
	sqlStr := fmt.Sprintf("INSERT INTO super_node SET `uid` = %d, name = '%s', wechat = '%s', des = '%s', phone_area = %d, phone_number = '%s', ",
		params.Uid, params.Name, params.Wechat, params.Des, params.PhoneArea, params.PhoneNumber)
	if len(params.Mark) > 0 {
		sqlStr += fmt.Sprintf("mark = '%s', ", params.Mark)
	}
	if len(params.Introduction) > 0 {
		sqlStr += fmt.Sprintf("introduction = '%s', ", params.Introduction)
	}
	sqlStr += fmt.Sprintf("create_time = %d", time.Now().Unix())
	Log("info", "新增超级节点 sql=", sqlStr)
	res := sqlx.MustExec(config.C.DB.DB, sqlStr)
	_, err = res.RowsAffected()
	if err != nil {
		Log("info", "新增超级节点失败：", err.Error())
		return errno.DbError
	}
	return
}

// 获取旷工角色信息
// Auth: hzp
type SuperMinerRoleResponse struct {
	Uid      int64 `json:"uid" db:"uid"`
	Status   int   `json:"status" db:"status"`
	SuperUid int64 `json:"super_uid" db:"super_uid"`
}

func GetSuperMinerRole(Uid int64) (res SuperMinerRoleResponse, err error) {

	err = sqlx.Get(config.C.DB.DB, &res, "SELECT t1.uid AS uid, t1.status AS `status`, t2.uid AS `super_uid` "+
		" FROM super_node_miner AS t1 LEFT JOIN super_node AS t2 ON t1.super_node_id = t2.node_id WHERE t1.uid = ?", Uid)
	if err != nil {
		return res, err
	}
	return res, nil
}
